// === Resize Image: minimalist surface, advanced controls under "More options" === var canvas = null; // legacy alias - latest output canvas var mimeType = 'image/png'; // legacy alias - latest output mime var originalImageObject = null; var originalFileName = ''; var originalDataUrl = ''; var originalMimeType = 'image/png'; var sourceBlobSize = 0; var sourceCanvas = null; var sourceWidth = 0; var sourceHeight = 0; var rotation = 0; var aspectLocked = true; var lockedAspect = 1; var outputFormatChoice = 'auto'; var outputQuality = 0.82; var cropEnabled = false; var currentBlob = null; var currentBlobUrl = null; var renderGeneration = 0; var renderDebounceTimer = null; var selectorMinSize = 24; var selectorRect = { x: 0, y: 0, width: 0, height: 0 }; var selectorDragMode = null; var selectorHandleCorner = null; var selectorStartX = 0; var selectorStartY = 0; var selectorStartRect = { x: 0, y: 0, width: 0, height: 0 }; var stretchDragMode = null; var stretchStartX = 0; var stretchStartY = 0; var stretchStartW = 0; var stretchStartH = 0; var stretchActive = false; var stretchDispScale = 1; function sliderToScale(pos) { return Math.pow(10, (pos - 500) / 250); } function scaleToSlider(scale) { if (!(scale > 0)) return 500; return clamp(500 + 250 * (Math.log(scale) / Math.LN10), 0, 1000); } function formatScale(scale) { if (!isFinite(scale) || 0 >= scale) return '100%'; if (scale >= 10) return scale.toFixed(scale >= 100 ? 0 : 1) + '×'; if (scale >= 1) { var pct = scale * 100; return (pct >= 200 ? Math.round(pct) : pct.toFixed(0)) + '%'; } if (scale >= 0.1) return Math.round(scale * 100) + '%'; return (scale * 100).toFixed(1) + '%'; } function updateScaleReadout(w, h) { if (!sourceWidth || !w) { $('#resize-scale-label').text('100%'); $('#resize-scale-dims').text(''); return; } var scale = w / sourceWidth; $('#resize-scale-label').text(formatScale(scale)); $('#resize-scale-dims').text(w + ' × ' + h); } function syncSliderFromDimensions() { var w = parseDimension('#image-width'); if (!w || !sourceWidth) return; $('#resize-scale-slider').val(Math.round(scaleToSlider(w / sourceWidth))); var h = parseDimension('#image-height') || 0; updateScaleReadout(w, h); } function isPositiveInteger(v) { return !isNaN(v) && v > 0 && v % 1 === 0; } function parseDimension(sel) { var v = parseInt($(sel).val(), 10); return isPositiveInteger(v) ? v : null; } function clamp(v, min, max) { return Math.min(Math.max(v, min), max); } function readableSize(bytes) { if (bytes == null || 0 >= bytes) return ''; if (1024 > bytes) return bytes + ' B'; if (1024 * 1024 > bytes) return Math.round(bytes / 1024) + ' KB'; return (bytes / (1024 * 1024)).toFixed(2) + ' MB'; } function getDisplaySize() { var el = $('#image-display')[0]; return el ? { width: el.clientWidth || 0, height: el.clientHeight || 0 } : { width: 0, height: 0 }; } function detectMimeFromName(name) { var l = (name || '').toLowerCase(); if (l.indexOf('.jpg') >= 0 || l.indexOf('.jpeg') >= 0) return 'image/jpeg'; if (l.indexOf('.png') >= 0) return 'image/png'; if (l.indexOf('.webp') >= 0) return 'image/webp'; if (l.indexOf('.gif') >= 0) return 'image/gif'; if (l.indexOf('.bmp') >= 0) return 'image/bmp'; if (l.indexOf('.tif') >= 0) return 'image/tiff'; return 'image/png'; } function getEffectiveFormat() { if (outputFormatChoice === 'auto') { if (originalMimeType === 'image/jpeg' || originalMimeType === 'image/png' || originalMimeType === 'image/webp') { return originalMimeType; } return 'image/png'; } return outputFormatChoice; } function getExtensionForFormat(fmt) { if (fmt === 'image/jpeg') return 'jpg'; if (fmt === 'image/png') return 'png'; if (fmt === 'image/webp') return 'webp'; return 'img'; } function isLossy(fmt) { return fmt === 'image/jpeg' || fmt === 'image/webp'; } function fileNameForOutput(fmt, w, h) { var base = originalFileName || 'image'; var dot = base.lastIndexOf('.'); var stem = dot > 0 ? base.substring(0, dot) : base; return stem + '-' + w + 'x' + h + '.' + getExtensionForFormat(fmt); } function buildSourceCanvas(img, rot) { var sc = document.createElement('canvas'); var sw = img.naturalWidth || img.width; var sh = img.naturalHeight || img.height; if (rot === 90 || rot === 270) { sc.width = sh; sc.height = sw; } else { sc.width = sw; sc.height = sh; } var ctx = sc.getContext('2d'); ctx.save(); ctx.translate(sc.width / 2, sc.height / 2); ctx.rotate(rot * Math.PI / 180); ctx.drawImage(img, -sw / 2, -sh / 2); ctx.restore(); return sc; } function rebuildSourceFromOriginalImage() { if (!originalImageObject) return; sourceCanvas = buildSourceCanvas(originalImageObject, rotation); sourceWidth = sourceCanvas.width; sourceHeight = sourceCanvas.height; lockedAspect = sourceWidth / sourceHeight; var previewSrc = rotation === 0 ? originalDataUrl : sourceCanvas.toDataURL(originalMimeType === 'image/jpeg' ? 'image/jpeg' : 'image/png', 0.92); $('#image-display').attr('src', previewSrc); $('#image-width').val(sourceWidth); $('#image-height').val(sourceHeight); $('#resize-scale-slider').val(500); updateScaleReadout(sourceWidth, sourceHeight); updateStretchedPreview(); if (cropEnabled) { window.requestAnimationFrame(initializeSelectorBox); } updateQualityVisibility(); scheduleRender(); } function getPreviewMaxBox() { var $wrap = $('.resize-preview'); var pad = 32; var maxW = Math.max(120, ($wrap.width() || 600) - pad); var maxH = 360; return { w: maxW, h: maxH }; } function updateStretchedPreview() { if (!sourceCanvas) return; var w = parseDimension('#image-width'); var h = parseDimension('#image-height'); if (!w || !h) return; if (aspectLocked) { $('#image-display').removeClass('is-stretched').css({ width: '', height: '' }); return; } var scale; if (stretchActive) { scale = stretchDispScale; } else { var box = getPreviewMaxBox(); scale = Math.min(box.w / w, box.h / h, 1); } var dispW = Math.max(1, Math.round(w * scale)); var dispH = Math.max(1, Math.round(h * scale)); $('#image-display').addClass('is-stretched').css({ width: dispW + 'px', height: dispH + 'px' }); } function getCropRectSourcePx() { if (!cropEnabled) return null; var ds = getDisplaySize(); if (!ds.width || !ds.height) return null; var sx = sourceWidth / ds.width; var sy = sourceHeight / ds.height; return { x: clamp(Math.round(selectorRect.x * sx), 0, sourceWidth - 1), y: clamp(Math.round(selectorRect.y * sy), 0, sourceHeight - 1), w: clamp(Math.round(selectorRect.width * sx), 1, sourceWidth), h: clamp(Math.round(selectorRect.height * sy), 1, sourceHeight) }; } function renderToBlob(targetW, targetH, format, quality) { return new Promise(function (resolve) { var out = document.createElement('canvas'); out.width = Math.max(1, Math.round(targetW)); out.height = Math.max(1, Math.round(targetH)); var ctx = out.getContext('2d'); if (format === 'image/jpeg') { ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, out.width, out.height); } ctx.imageSmoothingEnabled = true; ctx.imageSmoothingQuality = 'high'; var crop = getCropRectSourcePx(); if (crop) { ctx.drawImage(sourceCanvas, crop.x, crop.y, crop.w, crop.h, 0, 0, out.width, out.height); } else { ctx.drawImage(sourceCanvas, 0, 0, out.width, out.height); } try { out.toBlob(function (blob) { resolve({ blob: blob, canvas: out }); }, format, isLossy(format) ? quality : undefined); } catch (e) { resolve({ blob: null, canvas: out }); } }); } function scheduleRender() { if (renderDebounceTimer) clearTimeout(renderDebounceTimer); renderDebounceTimer = setTimeout(renderNow, 120); } function renderNow() { if (!sourceCanvas) return; var w = parseDimension('#image-width'); var h = parseDimension('#image-height'); if (!w || !h) { $('#downloadresizedimage').hide(); $('#resize-size-summary').text(''); $('#resize-format-summary').text(''); return; } var fmt = getEffectiveFormat(); var q = outputQuality; var gen = ++renderGeneration; renderToBlob(w, h, fmt, q).then(function (res) { if (gen !== renderGeneration) return; if (!res.blob) return; canvas = res.canvas; mimeType = fmt; currentBlob = res.blob; if (currentBlobUrl) URL.revokeObjectURL(currentBlobUrl); currentBlobUrl = URL.createObjectURL(res.blob); var fname = fileNameForOutput(fmt, w, h); $('#downloadresizedimage').attr('href', currentBlobUrl).attr('download', fname).show(); var origStr = readableSize(sourceBlobSize); var newStr = readableSize(res.blob.size); var summary = origStr ? (origStr + ' → ' + newStr) : newStr; if (sourceBlobSize > 0 && sourceBlobSize * 0.95 > res.blob.size) { var pct = Math.round(100 - (res.blob.size / sourceBlobSize) * 100); summary += ' (' + pct + '% smaller)'; } $('#resize-size-summary').text(summary); $('#resize-format-summary').text(getExtensionForFormat(fmt).toUpperCase()); }); } function updateQualityVisibility() { $('#resize-quality-row').toggle(isLossy(getEffectiveFormat())); } function setActiveChip($group, attr, value) { $group.find('.chip').removeClass('chip-on'); $group.find('.chip[data-' + attr + '="' + value + '"]').addClass('chip-on'); } // === Width / height typing with aspect lock === $('#image-width').on('input', function () { if (!sourceCanvas) return; var w = parseDimension('#image-width'); if (aspectLocked && w) { $('#image-height').val(Math.max(1, Math.round(w / lockedAspect))); } syncSliderFromDimensions(); updateStretchedPreview(); scheduleRender(); }); $('#image-height').on('input', function () { if (!sourceCanvas) return; var h = parseDimension('#image-height'); if (aspectLocked && h) { $('#image-width').val(Math.max(1, Math.round(h * lockedAspect))); } syncSliderFromDimensions(); updateStretchedPreview(); scheduleRender(); }); // === Aspect lock toggle === $('#aspect-lock').on('click', function () { aspectLocked = !aspectLocked; $(this).attr('aria-pressed', aspectLocked ? 'true' : 'false'); $('#resize-stage').toggleClass('is-unlocked', !aspectLocked); $('#resize-reset-dims').toggleClass('is-visible', !aspectLocked); if (aspectLocked) { var w = parseDimension('#image-width'); var h = parseDimension('#image-height'); if (w && h) lockedAspect = w / h; } updateStretchedPreview(); }); // === Scale slider (logarithmic) === $('#resize-scale-slider').on('input', function () { if (!sourceCanvas) return; var pos = parseInt($(this).val(), 10); var newScale = sliderToScale(pos); var oldW = parseDimension('#image-width') || sourceWidth; var oldH = parseDimension('#image-height') || sourceHeight; var w = clamp(Math.round(sourceWidth * newScale), 1, 20000); var h; if (aspectLocked) { h = clamp(Math.round(sourceHeight * newScale), 1, 20000); } else { var ratio = oldH / oldW; h = clamp(Math.round(w * ratio), 1, 20000); } $('#image-width').val(w); $('#image-height').val(h); updateScaleReadout(w, h); updateStretchedPreview(); scheduleRender(); }); // === Reset dimensions (shown when aspect unlocked) === $('#resize-reset-dims').on('click', function () { if (!sourceCanvas) return; $('#image-width').val(sourceWidth); $('#image-height').val(sourceHeight); $('#resize-scale-slider').val(500); updateScaleReadout(sourceWidth, sourceHeight); updateStretchedPreview(); scheduleRender(); }); // === Stretch handles (active when aspect unlocked) === function beginStretchDrag(e, mode) { if (!sourceCanvas || aspectLocked) return; var ev = e.type.indexOf('touch') === 0 ? e.originalEvent.touches[0] : e; stretchDragMode = mode; stretchStartX = ev.pageX; stretchStartY = ev.pageY; stretchStartW = parseDimension('#image-width') || sourceWidth; stretchStartH = parseDimension('#image-height') || sourceHeight; var ds = getDisplaySize(); var sx = (ds.width > 0 && stretchStartW > 0) ? (ds.width / stretchStartW) : 1; var sy = (ds.height > 0 && stretchStartH > 0) ? (ds.height / stretchStartH) : 1; stretchDispScale = Math.min(sx, sy); stretchActive = true; e.preventDefault(); e.stopPropagation(); } $('#resize-stretch-r').on('mousedown touchstart', function (e) { beginStretchDrag(e, 'r'); }); $('#resize-stretch-b').on('mousedown touchstart', function (e) { beginStretchDrag(e, 'b'); }); $('#resize-stretch-br').on('mousedown touchstart', function (e) { beginStretchDrag(e, 'br'); }); $(document).on('mousemove touchmove', function (e) { if (!stretchDragMode) return; var ev = e.type.indexOf('touch') === 0 ? e.originalEvent.touches[0] : e; var dx = ev.pageX - stretchStartX; var dy = ev.pageY - stretchStartY; var inv = stretchDispScale > 0 ? (1 / stretchDispScale) : 1; var w = stretchStartW, h = stretchStartH; if (stretchDragMode === 'r' || stretchDragMode === 'br') { w = Math.max(1, Math.min(20000, Math.round(stretchStartW + dx * inv))); } if (stretchDragMode === 'b' || stretchDragMode === 'br') { h = Math.max(1, Math.min(20000, Math.round(stretchStartH + dy * inv))); } $('#image-width').val(w); $('#image-height').val(h); syncSliderFromDimensions(); updateStretchedPreview(); scheduleRender(); e.preventDefault(); }); $(document).on('mouseup touchend touchcancel', function () { if (stretchDragMode) { stretchDragMode = null; stretchActive = false; updateStretchedPreview(); } }); // === Scale chips === $('#resize-scale-chips').on('click', '.chip', function () { if (!sourceCanvas) return; var s = parseFloat($(this).attr('data-scale')); var w = Math.max(1, Math.round(sourceWidth * s)); var h = Math.max(1, Math.round(sourceHeight * s)); lockedAspect = sourceWidth / sourceHeight; $('#image-width').val(w); $('#image-height').val(h); syncSliderFromDimensions(); updateStretchedPreview(); scheduleRender(); }); // === Preset dropdown === $('#resize-preset').on('change', function () { if (!sourceCanvas) return; var v = $(this).val(); if (!v) return; var parts = v.split('x'); var w, h; if (parts[1] === '_') { w = parseInt(parts[0], 10); h = Math.max(1, Math.round(w / (sourceWidth / sourceHeight))); } else if (parts[0] === '_') { h = parseInt(parts[1], 10); w = Math.max(1, Math.round(h * (sourceWidth / sourceHeight))); } else { w = parseInt(parts[0], 10); h = parseInt(parts[1], 10); } lockedAspect = w / h; $('#image-width').val(w); $('#image-height').val(h); syncSliderFromDimensions(); updateStretchedPreview(); scheduleRender(); }); // === Format chips === $('#resize-format-chips').on('click', '.chip', function () { outputFormatChoice = $(this).attr('data-format'); setActiveChip($('#resize-format-chips'), 'format', outputFormatChoice); updateQualityVisibility(); scheduleRender(); }); // === Quality slider === $('#resize-quality').on('input', function () { var v = parseInt($(this).val(), 10); outputQuality = v / 100; $('#resize-quality-value').text(v); scheduleRender(); }); // === Rotate chips === $('#resize-rotate-chips').on('click', '.chip', function () { if (!originalImageObject) return; var delta = parseInt($(this).attr('data-rotate'), 10); rotation = ((rotation + delta) % 360 + 360) % 360; rebuildSourceFromOriginalImage(); }); // === Crop toggle === $('#resize-crop-enable').on('change', function () { cropEnabled = this.checked; if (cropEnabled) { initializeSelectorBox(); $('#resize-selector').show(); } else { $('#resize-selector').hide(); } scheduleRender(); }); // === Advanced toggle === $('#resize-advanced-toggle').on('click', function () { var $adv = $('#resize-advanced'); var isHidden = $adv.is('[hidden]'); if (isHidden) { $adv.removeAttr('hidden'); $(this).attr('aria-expanded', 'true'); $(this).find('.resize-advanced-label').text('Fewer options'); } else { $adv.attr('hidden', ''); $(this).attr('aria-expanded', 'false'); $(this).find('.resize-advanced-label').text('More options'); } }); // === Target file size: binary search quality, then scale-down if needed === $('#resize-apply-target').on('click', function () { if (!sourceCanvas) return; var kb = parseInt($('#resize-target-kb').val(), 10); if (!isPositiveInteger(kb)) return; var target = kb * 1024; var w = parseDimension('#image-width'); var h = parseDimension('#image-height'); if (!w || !h) return; var fmt = getEffectiveFormat(); if (!isLossy(fmt)) { outputFormatChoice = 'image/jpeg'; setActiveChip($('#resize-format-chips'), 'format', 'image/jpeg'); updateQualityVisibility(); fmt = 'image/jpeg'; } fitTargetSize(w, h, fmt, target, 0); }); function fitTargetSize(w, h, fmt, target, attempt) { var lo = 0.30, hi = 0.95; var iters = 0; var bestQ = null; function trial() { if (iters >= 7) { finish(); return; } var mid = (lo + hi) / 2; renderToBlob(w, h, fmt, mid).then(function (res) { iters++; if (!res.blob) { finish(); return; } if (target >= res.blob.size) { bestQ = mid; lo = mid; } else { hi = mid; } trial(); }); } function finish() { if (bestQ != null) { outputQuality = bestQ; var pct = Math.round(bestQ * 100); $('#resize-quality').val(pct); $('#resize-quality-value').text(pct); scheduleRender(); return; } if (3 > attempt) { var nw = Math.max(1, Math.round(w * 0.82)); var nh = Math.max(1, Math.round(h * 0.82)); lockedAspect = nw / nh; $('#image-width').val(nw); $('#image-height').val(nh); fitTargetSize(nw, nh, fmt, target, attempt + 1); } else { outputQuality = 0.30; $('#resize-quality').val(30); $('#resize-quality-value').text(30); scheduleRender(); } } trial(); } // === Crop selector interaction === function clearSelectorInteraction() { selectorDragMode = null; selectorHandleCorner = null; } function renderSelector() { $('#resize-selector').css({ left: selectorRect.x + 'px', top: selectorRect.y + 'px', width: selectorRect.width + 'px', height: selectorRect.height + 'px' }); } function initializeSelectorBox() { var ds = getDisplaySize(); if (!ds.width || !ds.height) return; var minW = Math.min(selectorMinSize, ds.width); var minH = Math.min(selectorMinSize, ds.height); var margin = Math.max(8, Math.round(Math.min(ds.width, ds.height) * 0.10)); selectorRect.width = clamp(ds.width - margin * 2, minW, ds.width); selectorRect.height = clamp(ds.height - margin * 2, minH, ds.height); selectorRect.x = clamp(margin, 0, Math.max(0, ds.width - selectorRect.width)); selectorRect.y = clamp(margin, 0, Math.max(0, ds.height - selectorRect.height)); renderSelector(); } $('#resize-selector').on('mousedown', function (e) { if (!cropEnabled || !sourceCanvas) return; var cls = (e.target && e.target.className) || ''; if (typeof cls !== 'string') cls = cls.baseVal || ''; if (cls.indexOf('resize-handle-tl') >= 0) { selectorDragMode = 'resize'; selectorHandleCorner = 'tl'; } else if (cls.indexOf('resize-handle-tr') >= 0) { selectorDragMode = 'resize'; selectorHandleCorner = 'tr'; } else if (cls.indexOf('resize-handle-bl') >= 0) { selectorDragMode = 'resize'; selectorHandleCorner = 'bl'; } else if (cls.indexOf('resize-handle-br') >= 0) { selectorDragMode = 'resize'; selectorHandleCorner = 'br'; } else { selectorDragMode = 'move'; } selectorStartX = e.pageX; selectorStartY = e.pageY; selectorStartRect = { x: selectorRect.x, y: selectorRect.y, width: selectorRect.width, height: selectorRect.height }; e.preventDefault(); e.stopPropagation(); }); $(document).on('mousemove', function (e) { if (!selectorDragMode) return; var ds = getDisplaySize(); if (!ds.width || !ds.height) return; var minW = Math.min(selectorMinSize, ds.width); var minH = Math.min(selectorMinSize, ds.height); var dx = e.pageX - selectorStartX; var dy = e.pageY - selectorStartY; if (selectorDragMode === 'move') { selectorRect.x = clamp(selectorStartRect.x + dx, 0, Math.max(0, ds.width - selectorRect.width)); selectorRect.y = clamp(selectorStartRect.y + dy, 0, Math.max(0, ds.height - selectorRect.height)); } else { var sx = selectorStartRect.x, sy = selectorStartRect.y; var sw = selectorStartRect.width, sh = selectorStartRect.height; var nx = sx, ny = sy, nw = sw, nh = sh; if (selectorHandleCorner === 'br') { nw = clamp(sw + dx, minW, ds.width - sx); nh = clamp(sh + dy, minH, ds.height - sy); } else if (selectorHandleCorner === 'bl') { nx = clamp(sx + dx, 0, sx + sw - minW); nw = sx + sw - nx; nh = clamp(sh + dy, minH, ds.height - sy); } else if (selectorHandleCorner === 'tr') { ny = clamp(sy + dy, 0, sy + sh - minH); nh = sy + sh - ny; nw = clamp(sw + dx, minW, ds.width - sx); } else if (selectorHandleCorner === 'tl') { nx = clamp(sx + dx, 0, sx + sw - minW); nw = sx + sw - nx; ny = clamp(sy + dy, 0, sy + sh - minH); nh = sy + sh - ny; } selectorRect.x = nx; selectorRect.y = ny; selectorRect.width = nw; selectorRect.height = nh; } renderSelector(); scheduleRender(); e.preventDefault(); }); $(document).on('mouseup', clearSelectorInteraction); // === Download click: href already set; just fade in social === function download() { $('#social').fadeIn(5000); } if (typeof downloadresizedimage !== 'undefined' && downloadresizedimage) { downloadresizedimage.addEventListener('click', download, false); } // === Entry point - called by host when a file is dropped or chosen === function processFile(blob, fileName) { originalFileName = fileName; sourceBlobSize = (blob && blob.size) || 0; originalMimeType = (blob && blob.type) || detectMimeFromName(fileName); rotation = 0; aspectLocked = true; outputFormatChoice = 'auto'; outputQuality = 0.82; cropEnabled = $('#resize-crop-enable').is(':checked'); setActiveChip($('#resize-format-chips'), 'format', 'auto'); $('#resize-preset').val(''); $('#resize-quality').val(82); $('#resize-quality-value').text(82); $('#aspect-lock').attr('aria-pressed', 'true'); $('#resize-stage').removeClass('is-unlocked'); $('#resize-reset-dims').removeClass('is-visible'); $('#resize-scale-slider').val(500); var reader = new window.FileReader(); reader.readAsDataURL(blob); reader.onloadend = function () { originalDataUrl = reader.result; $('', { src: originalDataUrl }).on('load', function () { originalImageObject = this; $('#resize-empty-state').hide(); $('#resize-stage').css('display', 'inline-block'); $('#image-display').show(); $('#resize-toolbar').css('display', 'block'); $('#file-drop-zone').addClass('collapsedDropZone'); (function () { var $b = $('#file-drop-zone .upload-file-button'); var l = $b.data('change-label'); if (l) $b.text(l); })(); rebuildSourceFromOriginalImage(); window.requestAnimationFrame(function () { if (cropEnabled) initializeSelectorBox(); }); }); }; } var _loadedScripts = {}; function loadScriptPromise(url) { if (_loadedScripts[url]) return _loadedScripts[url]; _loadedScripts[url] = new Promise(function (resolve, reject) { var s = document.createElement('script'); s.src = url; s.onload = resolve; s.onerror = reject; document.head.appendChild(s); }); return _loadedScripts[url]; } function replaceAll(find, replace, str) { return str.replace(new RegExp(find, 'g'), replace); } function beautify(str) { var result = ''; var length = str.length; var i = 0; var braceCountLeft = 0; var braceCountRight = 0; var withinQuotes = false; while (i < length) { var c = str[i]; if (c == '"' && (i == 0 || c[i - 1] != '\\')) { // non-escaped quotes withinQuotes = !withinQuotes; } if (!withinQuotes && (c == '}' || c == '{' || c == ',')) { console.log('Start####' + result); // look back and remove carriage returns and whitespace that are already there var resultIndex = result.length - 1; while (resultIndex >= 0 && (result[resultIndex] == ' ' || result[resultIndex] == '\r' || result[resultIndex] == '\n' || result[resultIndex] == '\t')) { resultIndex = resultIndex - 1; result = result.substr(0, resultIndex + 1); console.log('char ' + result[resultIndex] + '-----' + result + 'zzz ' + result.length + ' ' + resultIndex); } if (c == '{') { braceCountLeft++; result += c + '\r' + GetTabs(braceCountLeft - braceCountRight); } else if (c == '}') { braceCountRight++; // precede with carriage return result += '\r' + GetTabs(braceCountLeft - braceCountRight) + c; } else if (c == ',') { result += c + '\r' + GetTabs(braceCountLeft - braceCountRight); } var nextChar = ''; // advance through whitespace and remove carriage returns that are already there while (i < length && (str[i + 1] == ' ' || str[i + 1] == '\r' || str[i + 1] == '\n' || str[i + 1] == '\t')) { i++; } } else { result += str[i]; } i++; } return result; } function GetTabs(count) { var result = ''; for (var i = 0; i < count; i++) { result += ' '; } return result; }